package signer

import (
	"fmt"
	"image"
	"image/color"
	"image/draw"
	"strings"

	"github.com/xjchan/freetype"
	"github.com/xjchan/freetype/truetype"
	"golang.org/x/image/font"
	"golang.org/x/image/math/fixed"
)

//Signer 作画数据结构,类似画笔,封装了字体,dpi,fontSize,行距,颜色,Hinting等参数
type Signer struct {
	Font     *truetype.Font
	Dpi      float64
	FontSize float64
	Pitch    float64
	Color    color.RGBA
	Hinting  font.Hinting
}

// Alignment 对齐标准
type Alignment int

const (
	Left Alignment = iota
	Center
	Right
)

// DrawStringImage 把文字写到背景上
// text 要填写的文字
// r 文本框
// alX, alY 垂直和水平对齐,支持Left,Center,Right
// bg 背景图片
//支持左对齐,居中,右对齐
func (signer *Signer) DrawStringImage(text string, r image.Rectangle, alX, alY Alignment, bg image.Image) (image.Image, error) {
	if len(text) == 0 {
		return bg, nil
	}
	ptSX, ptSY, ptEX, ptEY := r.Min.X, r.Min.Y, r.Max.X, r.Max.Y
	fg := &image.Uniform{signer.Color}
	rgba := image.NewRGBA(bg.Bounds())
	draw.Draw(rgba, rgba.Bounds(), bg, image.ZP, draw.Src)

	c := freetype.NewContext()
	c.SetDPI(signer.Dpi)
	c.SetFont(signer.Font)
	c.SetFontSize(signer.FontSize)
	c.SetClip(rgba.Bounds())
	c.SetDst(rgba)
	c.SetSrc(fg)
	c.SetHinting(signer.Hinting)
	// Draw the text.

	var getRealPtX func(x0, x1 int, s string) (realPtX int)
	var getRealPtY func(y0, y1 int, s string) (realPtY int)

	switch alX {
	case Left:
		getRealPtX = func(x0, x1 int, s string) (realPtX int) {
			return x0
		}
	case Center:
		getRealPtX = func(x0, x1 int, s string) (realPtX int) {
			width := x1 - x0
			strWidth := GetStringLen(signer, s)

			return (width-strWidth)/2 + x0
		}
	case Right:
		getRealPtX = func(x0, x1 int, s string) (realPtX int) {
			strWidth := GetStringLen(signer, s)
			// fmt.Println(strWidth)
			return x1 - strWidth
		}
	default:
		getRealPtX = func(x0, x1 int, s string) (realPtX int) {
			return x0
		}
	}

	switch alY {
	case Left:
		getRealPtY = func(y0, y1 int, s string) (realPtY int) {
			return y0
		}
	case Center:
		getRealPtY = func(y0, y1 int, s string) (realPtY int) {
			hight := y1 - y0
			strHight := GetLetterHeight(signer, s)

			return (hight-strHight)/2 + y0
		}
	case Right:
		getRealPtY = func(y0, y1 int, s string) (realPtY int) {
			// strHight := int(signer.FontSize * signer.Dpi * (64.0 / 72.0))
			strHight := GetLetterHeight(signer, s)
			fmt.Println(strHight)
			return y1 - strHight
		}
	default:
		getRealPtY = func(y0, y1 int, s string) (realPtY int) {
			return y0
		}
	}

	// realPtX, realPtY := getRealPt(ptSX, ptSY, strings.Split(text, "\n")[0])
	realPtX, realPtY := getRealPtX(ptSX, ptEX, text), getRealPtY(ptSY, ptEY, text)
	pt := freetype.Pt(realPtX, realPtY+int(c.PointToFixed(signer.FontSize).Floor()))
	// var err error
	for _, s := range strings.Split(text, "\n") {
		realX := getRealPtX(ptSX, ptEX, s)
		pt.X = fixed.I(realX)
		_, _ = c.DrawString(s, pt)
		pt.Y += c.PointToFixed(signer.FontSize * signer.Pitch)
	}

	return rgba, nil
}

//GetStringLen 算字符串长度
func GetStringLen(signer *Signer, s string) int {
	x := 0
	scale := fixed.Int26_6(signer.FontSize * signer.Dpi * (64.0 / 72.0))

	prev, hasPrev := truetype.Index(0), false
	for _, rune := range s {
		index := signer.Font.Index(rune)
		if hasPrev {
			kern := signer.Font.Kern(scale, prev, index)
			if signer.Hinting != font.HintingNone {
				kern = (kern + 32) &^ 63
			}
			x += kern.Floor()
		}
		glyph := truetype.GlyphBuf{}

		glyph.Load(signer.Font, scale, index, font.HintingFull)
		x += glyph.AdvanceWidth.Floor()
	}

	return x
}

func GetLetterHeight(signer *Signer, s string) int {
	y := 0
	scale := fixed.Int26_6(signer.FontSize * signer.Dpi * (64.0 / 72.0))
	// var h int
	prev, hasPrev := truetype.Index(0), false
	for _, rune := range s {
		index := signer.Font.Index(rune)
		if hasPrev {
			kern := signer.Font.Kern(scale, prev, index)
			if signer.Hinting != font.HintingNone {
				kern = (kern + 32) &^ 63
			}
			y += kern.Floor()
		}
		glyph := truetype.GlyphBuf{}

		glyph.Load(signer.Font, scale, index, font.HintingFull)
		if glyph.AdvanceHeight.Floor() > y {
			y = glyph.AdvanceHeight.Floor()
		}
	}
	fmt.Printf("AdvanceHeight:%d\n", y)
	return y
}
